from lib.metric_type.metric_type import Metric, MetricReader,\
    MetricSettingsException, Level, RangeAggregationType, InsAggregationType


class LatencyMetric(Metric):
    def __init__(self, metric_reader: MetricReader, metric_settings,
                 level: Level):
        super().__init__(metric_reader, metric_settings, level)

    def _process_latency_time_counter(
        self,
        range_agg_type: RangeAggregationType = RangeAggregationType.Increase,
        ins_agg_type: InsAggregationType = InsAggregationType.Sum
    ):
        three_weights = [0.1, 0.3, 0.6]
        two_weights = [0.3, 0.7]

        # query all latency range
        latency_range_result = []
        for range in self.settings.collect.related_value:
            latency_range_result.append(
                self._default_single_counter(
                    related_value=range,
                    range_agg_type=range_agg_type,
                    ins_agg_type=ins_agg_type
                )
            )

        final_value = None
        if len(latency_range_result) >= 3:
            partition = len(latency_range_result) // 3
            remainder = len(latency_range_result) % 3
            final_value = sum([
                weight * value
                for weight, value in zip(
                    three_weights,
                    [
                        sum(latency_range_result[:partition + remainder]),
                        sum(latency_range_result
                            [partition + remainder: partition * 2 + remainder]
                            ),
                        sum(latency_range_result[partition * 2 + remainder:])
                    ]
                )
            ])
        elif len(latency_range_result) == 2:
            final_value = two_weights[0] * latency_range_result[0] + \
                two_weights[1] * latency_range_result[1]
        else:
            final_value = latency_range_result[0]

        return final_value

    def _collect_process_metric(self) -> float:
        """
        We offer two standard method to process latency metric:
        standard_type = 1: the metric is already latency
        standard_type = 2: the metric is histogram
        """

        standard_type = self.settings.collect.standard_type
        if standard_type == 1:
            return super()._default_single_gauge()
        elif standard_type == 2:
            return self._process_latency_time_counter()
        else:
            raise MetricSettingsException(
                f'illegal standard type:{standard_type}'
            )

    def metric_score(self, pod: str, node: str,
                     cluster: str, last_end_time: float) -> (float, float):
        return super().metric_score(pod, node, cluster, last_end_time)
